﻿using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PMS.SANY.Entity;
using PMS.SANY.MonOrderServer.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PMS.SANY.MonOrderServer
{
    public class OrderServer
    {
        public ILogger<Worker> _logger;

        private bool enabledLoadOrder = false;

        /// <summary>
        /// 订单配置
        /// key=首工序工位编号；
        /// value=订单配置
        /// </summary>
        private Dictionary<string, OrderConfig> OrderConfig;

        /// <summary>
        /// 订单运行实例
        /// key=订单编号
        /// value=订单运行实例
        /// </summary>
        private Dictionary<string, OrderInstance> Instances;

        public OrderServer(ILogger<Worker> logger)
        {
            _logger = logger;
            Instances = new Dictionary<string, OrderInstance>();
            OrderConfig = new Dictionary<string, OrderConfig>();

            //球冠部件订单
            var oc = new OrderConfig() { Type = Enums.OrderType.球冠部件订单, Steps = new Dictionary<int, List<string>>() };
            oc.Steps.Add(0, new List<string> { "3505FH01A0010" });  //球冠自动焊接工位  0010
            OrderConfig.Add("3505FH01A0010", oc);

            //叶片部件订单
            oc = new OrderConfig() { Type = Enums.OrderType.叶片部件订单, Steps = new Dictionary<int, List<string>>() };
            oc.Steps.Add(0, new List<string> { "3505CX01A0010" });  //耐磨条堆焊工位   0010
            oc.Steps.Add(1, new List<string> { "3505CX01A0020" });  //油压成型工位     0020
            OrderConfig.Add("3505CX01A0010", oc);

            //锥桶部件订单
            oc = new OrderConfig() { Type = Enums.OrderType.锥桶部件订单, Steps = new Dictionary<int, List<string>>() };
            oc.Steps.Add(0, new List<string> { "3505FH02A0010" });  //拼版工位       0010
            //oc.Steps.Add(1, new List<string> { "3505FH02A0030" });  //纵焊缝工位     0030
            OrderConfig.Add("3505FH02A0010", oc);

            //整桶订单
            oc = new OrderConfig() { Type = Enums.OrderType.整桶订单, Steps = new Dictionary<int, List<string>>() };
            oc.Steps.Add(0, new List<string> { "3505JB01A0010" });                   //球冠压入        0010
            oc.Steps.Add(1, new List<string> { "3505JB01A0021", "3505JB01A0022" });  //立式组队(1,2)   0020
            oc.Steps.Add(2, new List<string> { "3505JB01A0031", "3505JB01A0032" });  //内环焊(1,2)     0030
            oc.Steps.Add(3, new List<string> { "3505JB01A0041", "3505JB01A0042", "3505JB01A0043" });  //摆搭(1,2,3)     0040
            oc.Steps.Add(4, new List<string> { "3505JB01A0051", "3505JB01A0052", "3505JB01A0053", "3505JB01A0054" });  //满焊(1,2,3,4)     0050
            oc.Steps.Add(1, new List<string> { "3505JB01A0061", "3505JB01A0062" });                     //合模(1,2)   0060
            //oc.Steps.Add(1, new List<string> { "3505JB01A0081", "3505JB01A0082", "3505JB01A0083" });    //外环焊(1,2,3)   0080
            OrderConfig.Add("3505JB01A0010", oc);
        }

        private async Task AutoLoadOrderAsync()
        {
            if (enabledLoadOrder) return;
            else enabledLoadOrder = true;

            while (enabledLoadOrder)
            {
                try
                {
                    using (var db = new GDbContextFactory().DbContext())
                    {
                        var list = await GetPlanAsync(db);
                        if (list != null || list.Count > 0)
                        {
                            foreach (var item in list)
                            {
                                if(!Instances.ContainsKey(item.WipOrderNo))
                                {
                                    OrderInstance ins = new OrderInstance();
                                    ins.Id = item.Id;
                                    ins.WipOrderNo = item.WipOrderNo;

                                    var seqlist = await db.OprSequence.Where(p => p.PlanId == item.Id && p.SequenceNo== "000000").ToListAsync();
                                    var firstSeq = (from u in seqlist where u.OprSequenceNo == "0010" select u).FirstOrDefault();
                                    ins.Config = OrderConfig[firstSeq.WorkStation];

                                    for (var idx = 0; idx < ins.Config.Steps.Count; idx++)
                                    {
                                        var seqCfg = ins.Config.Steps[idx];
                                        var stp = (from u in seqlist where seqCfg.Contains(u.WorkStation) select u).FirstOrDefault();

                                        var seqIns = new OprSequenceIns();
                                        seqIns.Id = stp.Id;
                                        seqIns.Quantity = stp.Quantity;
                                        seqIns.ActQuantity = stp.ActQuantity;
                                        seqIns.WorkStation = stp.WorkStation;
                                        seqIns.ProgressStatus = stp.ProgressStatus;
                                                                                
                                        ins.Steps.Add(idx, seqIns);
                                    }

                                    Instances.Add(item.WipOrderNo, ins);
                                }
                            }

                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError("AutoLoadOrderAsync error:" + ex.Message);
                }
                await Task.Delay(1000 * 30);
            }

            enabledLoadOrder = false;
        }

        private async Task<List<Plan>> GetPlanAsync(GDbContext db)
        {
            try
            {
                return await db.Plan
                    .Where(p => p.Deleted == false && p.Status == PlanStatus.Execute)
                    .OrderBy(o => o.IssuedTime)
                    .ToListAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError("GetPlan Error:" + ex.Message);
                return null;
            }
        }
    }
}
